#include "pch.h"
#include "SkinRenderer.h"
#include "Camera.h"
#include "RenderViewPort.h"
namespace mini
{
	CSkinRenderer::CSkinRenderer(CDevice* pDevice)
	:CRenderer(pDevice)
	{
		mOrder = 236;
		mRenderTypeFlag = RendererType::SkinRenderer;
	}

	CSkinRenderer::~CSkinRenderer()
	{

	}

	void CSkinRenderer::commitToGpu()
	{
	
		//if (mAttchEffects.size() > 0)
		//{
		//	for (auto item : mAttchEffects)
		//	{
		//		(item.second)->commitToGpu(mpDeferredContext);
		//	}
		//}
		//else
		{
			GEngine->getDevice()->turnZBufferStencilOff(mpDeferredContext);
			for (auto& item : mZbufferOffRenderUnitsPoint)
			{
				auto _item = (item.second);
				(_item.second)->renderPoint(mpDeferredContext);
			}

			for (auto& item : mRenderUnitsPoint)
			{
				for (auto& child : (item.second))
				{
					child->updateMatrices();
					(item.first)->setShader(mpDeferredContext);
					(item.first)->apply(mpDeferredContext);
					child->renderPoint(mpDeferredContext);
				}
			}
			for (auto& item : mAlphaRenderUnitsPoint)
			{
				for (auto& child : (item.second))
				{
					child->updateMatrices();
					(item.first)->setShader(mpDeferredContext);
					(item.first)->apply(mpDeferredContext);
					child->renderPoint(mpDeferredContext);
				}
			}

			CGPUBuffer* pBuffers[1] = { nullptr};
			UINT32 offset[1] = { 0 };
			mpDeferredContext->SOSetTargets(1, pBuffers, offset);

			GEngine->getDevice()->turnZBufferStencilOn(mpDeferredContext);
			for (auto& item : mZbufferOffRenderUnits)
			{
				auto _item = (item.second);
				(_item.second)->renderTriangleList(mpDeferredContext);
			}

			for (auto& item : mRenderUnits)
			{
				for (auto& child : (item.second))
				{
					(item.first)->setShader(mpDeferredContext);
					(item.first)->apply(mpDeferredContext);
					child->renderTriangleList(mpDeferredContext);
				}
			}
			for (auto& item : mAlphaRenderUnits)
			{
				for (auto& child : (item.second))
				{
					(item.first)->setShader(mpDeferredContext);
					(item.first)->apply(mpDeferredContext);
					child->renderTriangleList(mpDeferredContext);
				}
			}
		}
	}

	void CSkinRenderer::addUnit(CUnit* pUnit, CMaterialUnit* pMaterialUnit, EntityType Type, INT32 zLayer)
	{
		CSkinMeshUnit* pMeshUnit = dynamic_cast<CSkinMeshUnit*>(pUnit);
		if (nullptr != pMeshUnit)
		{
			CMaterialUnit* pMaterilaUnit = pMeshUnit->getMaterialUnit();
			if (pMaterilaUnit != nullptr)
			{
				for (int i = 0; i < pMaterilaUnit->getShaderUnitSize(); ++i)
				{
					CShaderUnit* pShaderUnit = pMaterilaUnit->getShaderUnit(i);
					if (pShaderUnit != nullptr)
					{
						pMaterilaUnit->updateMaterial();
						pShaderUnit->setWorldMatrix(&pMeshUnit->getMatrix());
						pShaderUnit->setViewMatrix(&mpCamera->getViewMatrix());
						pShaderUnit->setProjectMatrix(&mpCamera->getProjectMatrix());
						if (D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST == pShaderUnit->getShader()->getTopology())
						{
							if (pMaterilaUnit->isZbufferWrite())
							{
								if (pMaterilaUnit->isAlpha())
								{
									mAlphaRenderUnits[pShaderUnit].push_back(pMeshUnit);
								}
								else
								{
									mRenderUnits[pShaderUnit].push_back(pMeshUnit);
								}
							}
							else
							{
								mZbufferOffRenderUnits[zLayer] = std::make_pair(pShaderUnit, pMeshUnit);
							}
						}
						else
						{
							if (pMaterilaUnit->isZbufferWrite())
							{
								if (pMaterilaUnit->isAlpha())
								{
									mAlphaRenderUnitsPoint[pShaderUnit].push_back(pMeshUnit);
								}
								else
								{
									mRenderUnitsPoint[pShaderUnit].push_back(pMeshUnit);
								}
							}
							else
							{
								mZbufferOffRenderUnitsPoint[zLayer] = std::make_pair(pShaderUnit, pMeshUnit);
							}

						}
					}
				}
			}
		}
		for (auto item : mAttchEffects)
		{
			(item.second)->addUnit(pUnit, Type, zLayer);
		}
	}

	void CSkinRenderer::clearAllUnit()
	{
		CRenderer::clearAllUnit();
		mZbufferOffRenderUnitsPoint.clear();
		mRenderUnitsPoint.clear();
		mAlphaRenderUnitsPoint.clear();
	}

}

